// Copyright Leonid Shlyapnikov 2011
// Distributed under the GNU Lesser General Public License http://www.gnu.org/licenses/lgpl.html
//    author: Leonid Shlyapnikov, created on: Apr 1, 2011

#include "./FieldList.h"

#include <boost/exception/all.hpp>

#include <sstream>
#include <exception>

namespace fixparser {


const Field* debug_head_(const FieldList& list) {
    return list.head_;
}


std::out_of_range
FieldList::create_out_of_range_exception(size_t position) const {
    std::stringstream error;
    error << "Field position: " << position << " is out of range, list size: " << this->size_;
    return std::out_of_range(error.str());
}


void
FieldList::push_back(Field* field) {
    // linke the field
    back_->setNext(field);
    // make it the last element in the list
    back_ = field;
    // unlink anything from the current/last field
    back_->unlink();
    // bump up the list size
    size_++;
}


void
FieldList::clear() {
    this->size_ = 0;
    this->back_ = head_;
    this->back_->unlink();
    // not deleting any fields, MemoryArea::reset() supposed to handle it
}


Field*
FieldList::erase(size_t position) {
    if (position >= this->size_) {
        BOOST_THROW_EXCEPTION(create_out_of_range_exception(position));
    }

    // element that links to the one that we need to remove
    Field* prevNode = this->head_;
    for (size_t indx = 0; indx < position; indx++) {
        prevNode = prevNode->next_;
    }

    // element to be removed
    Field* node = prevNode->next_;
    // create a new link, skip the element that is being removed
    prevNode->next_ = node->next_;
    // unlink the one that is being removed
    node->unlink();

    this->size_--;

    return  node;
}


Field&
FieldList::operator[](size_t position) const {
    if (position >= this->size_) {
        BOOST_THROW_EXCEPTION(create_out_of_range_exception(position));
    }

    // element that links to the one that we need to find
    Field* prevNode = this->head_;
    for (size_t indx = 0; indx < position; indx++) {
        prevNode = prevNode->next_;
    }

    return *(prevNode->next_);
}

}
